<?php
/**
 * Routes urls to actions and viceversa
 *
 * Application specific routes must be set in /config/routes.php
 */
namespace PUF;

class Router {
	/**
	 * Router. Contains the only instance
	 */
	private static $instance = null;
	 
	/**
	 * String. Contains URL from where the page was called
	 */
	private $url = '/';
	
	/**
	 * String. Contains the root to prefix all URLs.
	 */
	private $webroot = '/';
	
	/**
	 * Dictionary of Route, indexed by url. Contains application specific routes.
	 */
	private $routes;
	
	private $plugins = [];
	
	/**
	 * Initializes required values
	 */
	private function __construct() {
		if (isset($_GET['url']) && $_GET['url'] != '') {
			$this->url = $_GET['url'];
			$this->webroot = substr($_SERVER['REQUEST_URI'], 0, -strlen($this->url));
			unset($_GET['url']);
			unset($_REQUEST['url']);
		} else {
			$this->webroot = $_SERVER['REQUEST_URI'];
		}
	}
	
	/**
	 * Returns the only instance
	 */
	public static function getInstance() {
		if (!self::$instance) {
			self::$instance = new Router();
		}
		
		return self::$instance;
	}
	
	/**
	 * Adds a custom Route.
	 */
	public function addRoute($route, $prefix = null) {
		if (!method_exists($route, 'getUrl')) {
			throw new \Exception(
				__METHOD__ . '() => $route is not from class Route!'
			);
		}
		if ($route->getUrl() == '') {
			throw new \Exception(
				__METHOD__ . '() => $route has not defined URL!'
			);
		}
		if ($route->getController() == '') {
			throw new \Exception(
				__METHOD__ . '() => $route has not defined Controller!'
			);
		}
		
		if ($prefix) {
			$this->routes[$prefix][$route->getUrl()] = $route;
		} else {
			$this->routes[$route->getUrl()] = $route;
		}
	}
	
	/**
	 * Returns controller to use given the URL
	 */
	public function getController() {
		$urlPieces = explode('/', $this->url);
		
		if ($plugin = $this->getPlugin()) {
			array_shift($urlPieces);
		}
		
		if (!$plugin && isset($this->routes[$this->url])) {
			return $this->routes[$this->url]->getController();
		}
		
		if (isset($urlPieces[0]) && $urlPieces[0] && strpos($urlPieces[0], ':') === false) {
			return ucfirst($urlPieces[0]);
		}
		
		if (!$plugin && !isset($this->routes['/'])) {
			throw new \Exception(
				__METHOD__ . '() => No default controller in /config/routes.php!'
			);
		}
		if ($plugin) {
			return $this->routes[$plugin->getPrefix()]['/']->getController();
		}
		return $this->routes['/']->getController();
	}
	
	/**
	 * Returns method to use given the URL
	 */
	public function getMethod() {
		$urlPieces = explode('/', $this->url);
		
		if ($plugin = $this->getPlugin()) {
			array_shift($urlPieces);
		}
		
		if (!$plugin && isset($this->routes[$this->url])) {
			return $this->routes[$this->url]->getMethod();
		}
		
		if (isset($urlPieces[1]) && $urlPieces[1]) {
			return $urlPieces[1];
		}
		
		if (!isset($this->routes['/'])) {
			throw new \Exception(
				__METHOD__ . '() => No default controller in /config/routes.php!'
			);
		}
		
		return $this->routes['/']->getMethod();
	}
	
	/**
	 * Returns to use given the URL
	 */
	public function getParams() {
		$urlPieces = explode('/', $this->url);
		
		if (strpos($urlPieces[0], ':') === false) {
			array_shift($urlPieces);
			array_shift($urlPieces);		
		}
		
		return implode('/', $urlPieces);
	}

	/**
	 * Return the webroot to prefix URLs
	 */
	public function getWebroot() {
		return $this->webroot;
	}
	
	public function addPlugin($plugin) {
		Loader::getInstance()->load($plugin, ['type' => 'plugin']);
		
		$namespacedName = 'PUF\\Plugin\\' . $plugin;
		
		$this->plugins[$plugin] = new $namespacedName();
		
		$prefix = $this->plugins[$plugin]->getPrefix();
		foreach ($this->plugins[$plugin]->getRoutes() as $route) {
			$this->addRoute($route, $prefix);
		}
	}
	
	public function getPlugin() {
		$urlPieces = explode('/', $this->url);
		
		if (isset($urlPieces[0])) {
			/** 
			 * We tell it to each Plugin to see if any of it takes over it
			 */
			foreach ($this->plugins as $plugin) {
				if (method_exists($plugin, 'getPrefix')) {
					if ($plugin->getPrefix() == $urlPieces[0]) {
						return $plugin;
					}
				}
			}
		}
		
		return null;
	}
	
	public function isAjax() {
		return isset($_SERVER['HTTP_X_REQUESTED_WITH'])
			&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
	}
}